package ru.pbem.olympia.battles;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.Predicate;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
 * User: Roman Pavlov
 * Date: 15-Oct-2010
 * Time: 14:21:07
 */
@SuppressWarnings({"UtilityClass"})
public class Simulator {
    private Simulator() {
    }

    public static void main(final String[] args) {
        Statistics stats = new Statistics();
        Battle battle = new G3Battle();
        final Combatant leaderOfAttack = new CombatUnit(80, 80, 0, 1, false);
        final List<List<Combatant>> attackers = new ArrayList<List<Combatant>>();
        //Simulator.addFighters(attackers, 1, 20, 15, 15, 0, 1, false);
        Simulator.addFighters(attackers, 1, 8, 25, 250, 25, 1, true);
        Simulator.addFighters(attackers, 2, 30, 5, 5, 25, 1, false);
        attackers.get(0).add(leaderOfAttack);

        final Combatant leaderOfDefense = new CombatUnit(5, 30, 0, 1, false);
        final List<List<Combatant>> defenders = new ArrayList<List<Combatant>>();
        Simulator.addFighters(defenders, 1, 99, 5, 30, 0, 1, false);
        defenders.get(0).add(leaderOfDefense);


        final Building building = new Building(0, 25, 0, 100, 50);

        for (int i = 0; i < 100000; i++) {
            final G3Army attacker = new G3Army(leaderOfAttack, attackers, null, true);
            final G3Army defender = new G3Army(leaderOfDefense, defenders, null, true);
            final Army winner = battle.fight(attacker, defender);
            stats.addBattleResult(attacker, defender, winner);
        }
        System.out.println(stats);
    }


    public static void addFighters(final List<List<Combatant>> army, final int line, final int num, final int attack,
                                   final int defense, final int rangedAttack, final int hitPoints, final boolean isSiege) {
        List<Combatant> band;
        if (line <= army.size()) {
            band = army.get(line-1);
        } else {
            band = new ArrayList<Combatant>();
            army.add(line - 1, band);
        }
        for (int i = 0; i < num; i++) {
            band.add(new CombatUnit(attack, defense, rangedAttack, hitPoints, isSiege));
        }
    }

    public static class Statistics {
        int attackerWins = 0;
        CasualtiesStatistics attackerStats = new CasualtiesStatistics();
        int defenderWins = 0;
        CasualtiesStatistics defenderStats = new CasualtiesStatistics();

        public void addBattleResult(Army attacker, Army defender, Army winner) {
            attackerWins += attacker == winner ? 1 : 0;
            attackerStats.process(getDead(attacker).size());
            defenderWins += defender == winner ? 1 : 0;
            defenderStats.process(getDead(defender).size());
        }

        public Collection<Combatant> getDead(Army army) {
            return CollectionUtils.select(army.getUnits(), new Predicate() {
                @Override
                public boolean evaluate(Object o) {
                    return !((FightingUnit) o).isAlive();
                }
            });
        }

        @Override
        public String toString() {
            return "Statistics{" + '\n' +
                    "\ttotal simulations= " + (attackerWins + defenderWins) + '\n' +
                    "\tchance attacker wins=" + (((float) attackerWins * 100) / (attackerWins + defenderWins)) + "%\n" +
                    "\tattacker casualties=" + attackerStats + '\n' +
                    "\tchance defender wins=" + (((float) defenderWins * 100) / (attackerWins + defenderWins)) + "%\n" +
                    "\tdefender casualties=" + defenderStats + '\n' +
                    '}';
        }
    }

    public static class CasualtiesStatistics {
        int min;
        int max;
        int total;
        int battles;

        public void process(int dead) {
            min = min < dead ? min : dead;
            max = max > dead ? max : dead;
            total += dead;
            battles++;
        }

        private float getAverage() {
            return total == 0 || battles == 0 ? 0 : ((float) total) / battles;
        }

        @Override
        public String toString() {
            return "CasualtiesStatistics{" +
                    "min=" + min +
                    ", max=" + max +
                    ", average=" + getAverage() +
                    '}';
        }
    }
}

